#include <lib/stddef.h>
#include <lib/stdio.h>
#include <lib/stdint.h>
#include <sys/ioctl.h>
#include <sys/res.h>
#include <sys/ioctl.h>
#include <os/debug.h>
#include <driver/view/screen.h>
#include <driver/view/mouse.h>
#include <driver/view/hal.h>
#include <driver/view/msg.h>
#include <driver/view/env.h>
#include <driver/view/render.h>
#include <driver/view/view.h>

view_mouse_t view_mouse;

static void ViewMouseDrawDefault(view_t *view);

// move view
static inline void ViewMouseMoveView()
{
    ViewSetXY(view_mouse.view, view_mouse.x + view_mouse.view_off_x, view_mouse.y + view_mouse.view_off_y);
}

static inline void MouseMotion()
{
    view_mouse.x%=view_screen.width;
    view_mouse.y%=view_screen.height;

    //KPrint("view mouse xy %d %d\n",view_mouse.x,view_mouse.y);

    // move mouse
    ViewMouseMoveView();

    view_msg_t msg;
    ViewMsgHeader(&msg, VIEW_MSG_MOUSE_MOTION, VIEW_TARGE_NONE);
    ViewMsgData(&msg, view_mouse.x, view_mouse.y, 0, 0);
    ViewPutGlobalMsg(&msg);
}

static inline void MouseWheel(int wheel)
{
    int id = (wheel) ? VIEW_MSG_MOUSE_WHEEL_UP : VIWE_MSG_MOUSE_WHEEL_DOWN;
    view_msg_t msg;
    ViewMsgHeader(&msg, id, VIEW_TARGE_NONE);
    ViewMsgData(&msg, view_mouse.x, view_mouse.y, 0, 0);
    ViewPutGlobalMsg(&msg);
}

static inline void MouseButtonDown(int button)
{
    int id = -1;
    switch (button)
    {
    case 0:
        id = VIEW_MSG_MOUSE_LBTN_DOWN;
        break;
    case 1:
        id = VIEW_MSG_MOUSE_MBTN_DOWN;
        break;
    case 2:
        id = VIEW_MSG_MOUSE_RBTN_DOWN;
        break;
    default:
        break;
    }

    // KPrint("view mouse down msg %d\n",id);

    view_msg_t msg;
    ViewMsgHeader(&msg, id, VIEW_TARGE_NONE);
    ViewMsgData(&msg, view_mouse.x, view_mouse.y, 0, 0);
    ViewPutGlobalMsg(&msg);
}

static inline void MouseButtonUp(int button)
{
    int id = -1;
    switch (button)
    {
    case 0:
        id = VIEW_MSG_MOUSE_LBTN_UP;
        break;
    case 1:
        id = VIEW_MSG_MOUSE_MBTN_UP;
        break;
    case 2:
        id = VIEW_MSG_MOUSE_RBTN_UP;
        break;
    default:
        break;
    }

    // KPrint("view mouse up msg %d\n",id);

    view_msg_t msg;
    ViewMsgHeader(&msg, id, VIEW_TARGE_NONE);
    ViewMsgData(&msg, view_mouse.x, view_mouse.y, 0, 0);
    ViewPutGlobalMsg(&msg);
}

int ViewMouseInit()
{
    if (ViewMouseOpen(&view_mouse) < 0)
        return -1;

    view_mouse.motion = MouseMotion;
    view_mouse.button_down = MouseButtonDown;
    view_mouse.button_up = MouseButtonUp;
    view_mouse.wheel = MouseWheel;
    view_mouse.x = 0;
    view_mouse.y = 0;

    view_mouse.view_off_x = view_mouse.view_off_y = 0;
    view_mouse.local_x = view_mouse.local_y = 0;
    view_mouse.click_x = view_mouse.click_y = 0;
    view_mouse.status = VIEW_MOUSE_NORMAL;

    // create status bmp
    int i;
    for (i = 0; i < VIEW_MOUSE_STATUS_NUM; i++)
    {
        view_mouse.status_table[i].bmp = NULL;
        view_mouse.status_table[i].off_x = 0;
        view_mouse.status_table[i].off_y = 0;
    }

    // create view
    view_t *view = ViewCreate(view_mouse.x, view_mouse.y, VIEW_MOUSE_SIZE, VIEW_MOUSE_SIZE, 0);
    if (!view)
    {
        KPrint("[view] view create err\n");
        return -1;
    }
    view_mouse.view = view;

    ViewSetType(view, VIEW_TYPE_FIXED);

    // drag mouse status
    ViewMouseDraw(view_mouse.status);
    // show mouse view
    ViewSetZ(view, 0);

    // set mouse view to middle
    ViewEnvSetMiddle(view);
    return 0;
}

int ViewMouseExit()
{
    if (view_mouse.view) // free view
    {
        ViewHide(view_mouse.view);
        ViewDestroy(view_mouse.view);
        view_mouse.view = NULL;
    }
    ViewMouseClose(&view_mouse); // close
}

static void ViewMouseSetViewOff(int x, int y)
{
    view_mouse.view_off_x = x;
    view_mouse.view_off_y = y;
}

int ViewMouseShow()
{
    if (!view_mouse.view)
        return -1;
    if (view_mouse.view->z < 0)
        return ViewMoveToTop(view_mouse.view);
    return -1;
}

int ViewMouseGetStatus(view_mouse_status_t *status)
{
    if (!status)
        return -1;
    *status = view_mouse.status;
    return 0;
}

int ViewMouseSetStatus(view_mouse_status_t status)
{\
    view_mouse.status = status;
    ViewMouseDraw(status);
}

int ViewMouseIsStatus(view_mouse_status_t status)
{
    return view_mouse.status == status;
}

int ViewMouseHide()
{
    if (!view_mouse.view)
        return -1;
    if (view_mouse.view->z > 0)
        return ViewHide(view_mouse.view);
    return -1;
}


void ViewMouseDraw(view_mouse_status_t status)
{
    if (status >= VIEW_MOUSE_STATUS_NUM)
        return;
    view_mouse_status_info_t *info = &view_mouse.status_table[status];
    ViewRenderClear(view_mouse.view);
    if (info->bmp)
    {
        //KPrint("[view mouse] draw cursor from cursor info status %d\n",info->status);
        // copy bitmap to view
        ViewRenderBitblt(view_mouse.view, 0, 0, info->bmp, 0, 0, info->bmp->width, info->bmp->height);
        ViewMouseSetViewOff(info->off_x, info->off_y);
    }
    else
    {
        // draw default view
        ViewMouseDrawDefault(view_mouse.view);
        ViewMouseSetViewOff(-view_mouse.view->width / 2, -view_mouse.view->height / 2);
    }
    // move view
    ViewMouseMoveView();
}

static void ViewMouseDrawDefault(view_t *view)
{
    ViewRenderVline(view, view->width / 2 + 1, 0, view->height - 1, VIEW_BLACK);
    ViewRenderHline(view, 0, view->height / 2 + 1, view->width - 1, VIEW_BLACK);

    ViewRenderVline(view, view->width / 2, 0, view->height - 1, VIEW_WHITE);
    ViewRenderHline(view, 0, view->height / 2, view->width - 1, VIEW_WHITE);
}

int ViewMouseSetStatusInfo(view_mouse_status_info_t info)
{
    view_mouse_status_t status = info.status;
    if (status >= VIEW_MOUSE_STATUS_NUM)
        return -1;
    if (!info.bmp)
        return -1;

    view_mouse_status_info_t *_info = &view_mouse.status_table[status];
    if (!_info->bmp)
    {
        // create new bitmap
        _info->bmp = ViewBitmapCreate(info.bmp->width, info.bmp->height);
        if (!_info->bmp)
            return -1;
    }
    else
    {
        ViewBitmapClear(_info->bmp); // clear
    }

    // copy bitmap data
    ViewBitmapBlit(info.bmp,NULL, _info->bmp, NULL);
    
    _info->off_x = info.off_x;
    _info->off_y = info.off_y;
    _info->status=info.status;

    return 0;
}

int ViewMouseGetStatusInfo(view_mouse_status_info_t *info)
{
    view_mouse_status_t status = info->status;
    if (status >= VIEW_MOUSE_STATUS_NUM)
        return -1;
    if (!info->bmp)
        return -1;
    view_mouse_status_info_t *_info = &view_mouse.status_table[status];
    if (!_info->bmp)
        return -1;
    // copy data
    ViewBitmapBlit(_info->bmp, NULL, info->bmp, NULL);
    info->off_x = _info->off_x;
    info->off_x = _info->off_y;
    return 0;
}
